package goods

import (
	"github.com/shopspring/decimal"
	"shopstar/core/cache"
	"shopstar/models"
	"shopstar/models/goods"
	"shopstar/util"
	"strconv"
	"strings"
)

type Sku struct {
}

var SkuService = new(Sku)

// CateList 先有一个页面添加属性和属性值 =》 再点击组合对应的sku
func (service *Sku) CateList(goodsId int64) [][]goods.AttributeDetail {
	attrs, _ := GoodsService.GoodsAttributeList(goodsId)
	attrValues := make([][]goods.AttributeDetail, len(attrs))

	//fmt.Println(attrs)
	for k, v := range attrs {
		attrValues[k] = v.Detail
	}
	//fmt.Println(attrValues)
	return service.reBuildList(attrValues)
}

func (*Sku) reBuildList(attrValues [][]goods.AttributeDetail) (data [][]goods.AttributeDetail) {
	lens := func(i int) int { return len(attrValues[i]) }

	next := func(record []int, lens func(i int) int) {
		for i := len(record) - 1; i >= 0; i-- {
			record[i]++

			if record[i] < lens(i) || i == 0 {
				return
			}

			record[i] = 0
		}
	}
	// 记录对应数组的元素获取位置
	record := make([]int, len(attrValues))
	//fmt.Println(record)

	for record[0] < lens(0) {
		// 记录组合的结果
		tmp := make([]goods.AttributeDetail, len(attrValues))

		for k, v := range record {
			tmp[k] = attrValues[k][v]
		}

		data = append(data, tmp)

		next(record, lens)
	}

	return
}

func (*Sku) Add(goodsId int64, title, properties string, price decimal.Decimal, stock int) error {
	sku := goods.GoodsSku{
		Title:      title,
		Properties: properties,
		Price:      price,
		Stock:      stock,
		GoodsId:    goodsId,
	}

	return models.DB.Create(&sku).Error
}

func (service *Sku) Skus(goodsId int64) (sku []goods.GoodsSku) {
	models.DB.Where("goods_id = ?", goodsId).Find(&sku)
	return
}

// SkuAttrCollection 取交集的方法，输入要搜索的sku，判断出和其有关联的sku值
func (service *Sku) SkuAttrCollection(goodsId int64, skuProperties string) map[int64]*util.GraphAttr {
	key := "goodsId_" + strconv.Itoa(int(goodsId))
	var g *util.Graph
	// 去缓存中读取sku的列表图
	graph, err := cache.CacheManager.Get(key)
	if err == nil && len(graph.([]byte)) > 0 {
		// 存在则取出
		g, _ = util.LoadGraphMsgPack(graph.([]byte))
	} else {
		// 获取图，序列化，存入缓存
		g = SkuService.attrGraph(goodsId)
		cache.CacheManager.Set(key, g.ExportMsgPack(), &cache.Options{})
	}
	// 执行属性的筛选
	if skuProperties == "" {
		//fmt.Println(g.Collection(""))
		return g.Collection("")
	}

	return g.Collection(strings.Split(skuProperties, ",")...)
}

// attrGraph 画sku的图并且做标记
// 比如
//
//	蓝色8cm 蓝色5cm 黑色7cm 粉色7cm 紫色5cm 34码    35码    36码    37码    38码
//
// 蓝色8cm 0       1       1       1       1       0       0       1       1       1
// 蓝色5cm 1       0       1       1       1       1       1       1       1       0
// 黑色7cm 1       1       0       1       1       1       0       1       1       0
// 粉色7cm 1       1       1       0       1       0       0       1       1       1
// 紫色5cm 1       1       1       1       0       1       1       0       1       0
// 34码    0       1       1       0       1       0       1       1       1       1
// 35码    0       1       0       0       1       1       0       1       1       1
// 36码    1       1       1       1       0       1       1       0       1       1
// 37码    1       1       1       1       1       1       1       1       0       1
// 38码    1       0       0       1       0       1       1       1       1       0
func (service *Sku) attrGraph(goodsId int64) *util.Graph {
	attrs, _ := GoodsService.GoodsAttributeList(goodsId)
	//fmt.Println(attrs)
	g := util.NewGraph(GoodsService.GoodsAttributeCount(goodsId))
	// 作图
	for _, attr := range attrs {
		for _, v := range attr.Detail {
			//fmt.Println("k == > ", k, "  name ==> ", attr.Name, "  v == >", v)
			ids := strconv.Itoa(int(attr.Id)) + ":" + strconv.Itoa(int(v.Id))
			g.AddNode(attr.Id, ids, v.Name)

			g.AddAttrs(attr.Name, &util.GraphAttrVal{
				Ids:   ids,
				Super: attr.Id,
				Title: v.Name,
			})
		}
	}
	// 标记
	for _, v := range SkuService.Skus(goodsId) {
		g.AddVertex(strings.Split(v.Properties, ";"))
	}
	return g
}
